using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ploeh.AutoFixture;
using System.IO;
using FileDownloadServer;
using ArtOfTest.WebAii.Core;
using ArtOfTest.WebAii.Win32.Dialogs;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UITesting;
using Tests.Properties;
using System.Web.Http;
using Microsoft.VisualStudio.TestTools.UnitTesting.Web;
using System.Linq;
using FluentAssertions;
using ArtOfTest.Common.Win32;
using System.Diagnostics;
using System.Net.Sockets;
using System.Net;

namespace Tests
{
	class WebApplicationLauncher
	{
		private readonly Directory webApplicationPath;

		public WebApplicationLauncher(Directory webApplicationPath)
		{
			this.webApplicationPath = webApplicationPath;
		}

		public async Task<WebApplication> Start()
		{
			Process webServer = null;
			try
			{
				var port = GetFreePort();
				webServer = MakeProcess(port);
				webServer.Start();
				await Task.Run(() => FinishLoading(webServer));

				return new WebApplication(webServer, MakeAddress(port));
			}
			catch
			{
				if (webServer != null)
					webServer.Dispose();
				throw;
			}
		}

		private static int GetFreePort()
		{
			var tcpListener = new TcpListener(IPAddress.Loopback, 0);
			tcpListener.Start();
			var port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
			tcpListener.Stop();
			return port;
		}

		private void FinishLoading(Process webServer)
		{
			if (!webServer.WaitForInputIdle())
				throw new Exception("Web server didn't enter idle state.");
		}

		private Process MakeProcess(int port)
		{
			var webServer = new Process
			{
				StartInfo = new ProcessStartInfo
				{
					Arguments = String.Format("/port:{0} /path:\"{1}\"", port, webApplicationPath.AbsolutePath),
					FileName = WebServerPath,
					RedirectStandardError = true,
					UseShellExecute = false
				}
			};

			return webServer;
		}

		private static string WebServerPath
		{
			get
			{
				return Path.Combine(CommonFilesPath, "Microsoft Shared", "DevServer", "11.0", "WebDev.WebServer40.EXE");
			}
		}

		private static string CommonFilesPath
		{
			get
			{
				return Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFilesX86);
			}
		}

		private Uri MakeAddress(int port)
		{
			return new Uri("http://localhost:" + port);
		}
	}
}